﻿using System.IO;
using System.Xml;
using BuzzX8.Xmpp.StreamElements;
using NUnit.Framework;

namespace BuzzX8.Xmpp.Test
{
    public static class XmlAssert
    {
        public static void AreEquals(StreamElement expectedElement, StreamElement actualElement)
        {
            if (expectedElement == null && actualElement == null) return;
            if ((expectedElement == null && actualElement != null) || 
                 expectedElement != null && actualElement == null) Assert.Fail();
            AreEquals(expectedElement.ToString(), actualElement.ToString());
        }

        public static void AreEquals(StreamElement expected, string actual)
        {
            AreEquals(expected.ToString(), actual);
        }

        public static void AreEquals(string expectedXml, string actualXml)
        {
            XmlReader actualXmlReader = CreateXmlReader(actualXml);
            XmlReader expectedXmlReader = CreateXmlReader(expectedXml);

            try
            {
                AreEquals(expectedXmlReader, actualXmlReader);
            }
            finally
            {
                actualXmlReader.Close();
                expectedXmlReader.Close();
            }
        }

        private static XmlReader CreateXmlReader(string xml)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreWhitespace = true;
            return XmlReader.Create(new StringReader(xml), settings);
        }

        private static void AreEquals(XmlReader expectedXmlReader, XmlReader actualXmlReader)
        {
            while(!expectedXmlReader.EOF || !actualXmlReader.EOF)
            {
                expectedXmlReader.Read();
                actualXmlReader.Read();
                AreEqualElements(expectedXmlReader, actualXmlReader);
            }
            if (!expectedXmlReader.EOF || !actualXmlReader.EOF) Assert.Fail("Elements have different nodes count");
        }

        private static void AreEqualElements(XmlReader elementReader1, XmlReader elementReader2)
        {
            Assert.AreEqual(elementReader1.Name, elementReader2.Name, "Elements nodes has different names");
            Assert.AreEqual(elementReader1.NamespaceURI, elementReader2.NamespaceURI, "Elements nodes has different namespace URIs");
            Assert.AreEqual(elementReader1.Depth, elementReader2.Depth, "");
            AreEqualAttributes(elementReader1, elementReader2);
        }

        private static void AreEqualAttributes(XmlReader elementReader1, XmlReader elementReader2)
        {
            if (!elementReader1.HasAttributes && !elementReader2.HasAttributes) return;
            Assert.AreEqual(elementReader1.AttributeCount, elementReader2.AttributeCount, "Elements or child nodes has different attribute count");
            VerifyElementAttribute(elementReader1, elementReader2);
            
        }

        private static void VerifyElementAttribute(XmlReader elementReader1, XmlReader elementReader2)
        {
            elementReader1.MoveToFirstAttribute();
            do
            {
                if (!elementReader2.MoveToAttribute(elementReader1.Name)) Assert.Fail("");
                Assert.AreEqual(elementReader1.Prefix, elementReader2.Prefix, "");
                Assert.AreEqual(elementReader1.NamespaceURI, elementReader2.NamespaceURI, "");
                Assert.AreEqual(elementReader1.Value, elementReader2.Value);
                
            } while (elementReader1.MoveToNextAttribute());
            elementReader1.MoveToElement();
            elementReader2.MoveToElement();
        }
    }
}
